home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / mint96sb.zoo / src / filesys.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-10-10  |  23.8 KB  |  985 lines

  1. /*
  2. Copyright 1990,1991,1992 Eric R. Smith. All rights reserved.
  3. */
  4.  
  5. /*
  6.  * various file system interface things
  7.  */
  8.  
  9. #include "mint.h"
  10.  
  11. FILESYS *active_fs;
  12. FILESYS *drives[NUM_DRIVES];
  13.  
  14. /* "aliased" drives are different names
  15.  * for real drives/directories
  16.  * if drive d is an alias for c:\usr,
  17.  * then alias_drv[3] == 2 (the real
  18.  * drive) and aliases has bit (1L << 3)
  19.  * set.
  20.  * NOTE: if aliasdrv[d] is 0, then d is not an aliased drive,
  21.  * otherwise d is aliased to drive aliasdrv[d]-1
  22.  * (e.g. if drive A: is aliased to B:\FOO, then
  23.  * aliasdrv[0] == 'B'-'A'+1 == 2). Always remember to
  24.  * compensate for the extra 1 when dereferencing aliasdrv!
  25.  */
  26. int    aliasdrv[NUM_DRIVES];
  27.  
  28. FILEPTR *flist;        /* a list of free file pointers */
  29.  
  30. char follow_links[1];    /* dummy "name" used as a parameter to path2cookie */
  31.  
  32. /* vector of valid drives, according to GEMDOS */
  33. /* note that this isn't necessarily the same as what the BIOS thinks of
  34.  * as valid
  35.  */
  36. long dosdrvs;
  37.  
  38. /*
  39.  * Initialize a specific drive. This is called whenever a new drive
  40.  * is accessed, or when media change occurs on an old drive.
  41.  * Assumption: at this point, active_fs is a valid pointer
  42.  * to a list of file systems.
  43.  */
  44.  
  45. /* table of processes holding locks on drives */
  46. extern PROC *dlockproc[];    /* in dosdir.c */
  47.  
  48. void
  49. init_drive(i)
  50.     int i;
  51. {
  52.     long r;
  53.     FILESYS *fs;
  54.     fcookie root_dir;
  55.  
  56.     TRACE(("init_drive(%c)", i+'A'));
  57.  
  58.     drives[i] = 0;        /* no file system */
  59.     if (i >= 0 && i < NUM_DRIVES) {
  60.         if (dlockproc[i]) return;
  61.     }
  62.  
  63.     for (fs = active_fs; fs; fs = fs->next) {
  64.         r = (*fs->root)(i, &root_dir);
  65.         if (r == 0) {
  66.             drives[i] = root_dir.fs;
  67.             break;
  68.         }
  69.     }
  70. }
  71.  
  72. /*
  73.  * initialize the file system
  74.  */
  75.  
  76. #define NUMFPS    40    /* initial number of file pointers */
  77.  
  78. void
  79. init_filesys()
  80. {
  81.     static FILEPTR initial[NUMFPS+1];
  82.     int i;
  83.     extern FILESYS tos_filesys, bios_filesys, pipe_filesys,
  84.         proc_filesys, uni_filesys;
  85.  
  86. /* get the vector of connected GEMDOS drives */
  87.     dosdrvs = Dsetdrv(Dgetdrv()) | drvmap();
  88.  
  89. /* set up some initial file pointers */
  90.     for (i = 0; i < NUMFPS; i++) {
  91.         initial[i].devinfo = (ulong) (&initial[i+1]);
  92.     }
  93.     initial[NUMFPS].devinfo = 0;
  94.     flist = initial;
  95.  
  96. /* set up the file systems */
  97.     tos_filesys.next = 0;
  98.     bios_filesys.next = &tos_filesys;
  99.     pipe_filesys.next = &bios_filesys;
  100.     proc_filesys.next = &pipe_filesys;
  101.     uni_filesys.next = &proc_filesys;
  102.  
  103.     active_fs = &uni_filesys;
  104.  
  105. /* initialize the BIOS file system */
  106.     biosfs_init();
  107.  
  108. /* initialize the unified file system */
  109.     unifs_init();
  110. }
  111.  
  112. /*
  113.  * load file systems from disk
  114.  * this routine is called after process 0 is set up, but before any user
  115.  * processes are run
  116.  *
  117.  * NOTE that a number of directory changes take place here: we look first
  118.  * in the current directory, then in the directory \mint, and finally
  119.  * the d_lock() calls force us into the root directory.
  120.  */
  121.  
  122. typedef FILESYS * ARGS_ON_STACK (*FSFUNC) P_((struct kerinfo *));
  123.  
  124. void
  125. load_filesys()
  126. {
  127.     long r;
  128.     BASEPAGE *b;
  129.     FILESYS *fs;
  130.     FSFUNC initf;
  131.     static DTABUF dta;
  132.     int i;
  133.     extern struct kerinfo kernelinfo; /* in main.c */
  134.     char curpath[PATH_MAX];
  135. #define NPATHS 2
  136.     static const char *paths[NPATHS] = {"", "\\MINT"};
  137.  
  138.     curproc->dta = &dta;
  139.     d_getpath(curpath,0);
  140.  
  141.     for (i = 0; i < NPATHS; i++) {
  142.         if (*paths[i]) {
  143. /* don't bother checking the current directory twice! */
  144.             if (!stricmp(paths[i],curpath))
  145.             r = -1;
  146.             else
  147.             r = d_setpath(paths[i]);
  148.         }
  149.         else
  150.             r = 0;
  151.  
  152.         if (r == 0)
  153.             r = f_sfirst("*.xfs", 0);
  154.  
  155.         while (r == 0) {
  156.         b = (BASEPAGE *)p_exec(3, dta.dta_name, (char *)"", (char *)0);
  157.         if ( ((long)b) < 0 ) {
  158.             DEBUG(("Error loading file system %s", dta.dta_name));
  159.             r = f_snext();
  160.             continue;
  161.         }
  162.     /* we leave a little bit of slop at the end of the loaded stuff */
  163.         m_shrink(0, (virtaddr)b, 512 + b->p_tlen + b->p_dlen + b->p_blen);
  164.         initf = (FSFUNC)b->p_tbase;
  165.         TRACE(("initializing %s", dta.dta_name));
  166.         fs = (*initf)(&kernelinfo);
  167.  
  168.         if (fs) {
  169.             TRACE(("%s loaded OK", dta.dta_name));
  170.             fs->next = active_fs;
  171.             active_fs = fs;
  172.         } else {
  173.             DEBUG(("%s returned null", dta.dta_name));
  174.         }
  175.         r = f_snext();
  176.         }
  177.     }
  178.  
  179. /* here, we invalidate all old drives EXCEPT for ones we're already using (at
  180.  * this point, only the bios devices should be open)
  181.  * this gives newly loaded file systems a chance to replace the
  182.  * default tosfs.c
  183.  */
  184.     for (i = 0; i < NUM_DRIVES; i++) {
  185.         if (d_lock(1, i) == 0)    /* lock if possible */
  186.             d_lock(0, i);    /* and then unlock */
  187.     }
  188. }
  189.  
  190. void
  191. close_filesys()
  192. {
  193.     PROC *p;
  194.     FILEPTR *f;
  195.     int i;
  196.  
  197.     TRACE(("close_filesys"));
  198. /* close every open file */
  199.     for (p = proclist; p; p = p->gl_next) {
  200.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  201.             if ( (f = p->handle[i]) != 0) {
  202.                 if (p->wait_q == TSR_Q || p->wait_q == ZOMBIE_Q)
  203.                     ALERT("Open file for dead process?");
  204.                 do_pclose(p, f);
  205.             }
  206.         }
  207.     }
  208. }
  209.  
  210. /*
  211.  * "media change" routine: called when a media change is detected on device
  212.  * d, which may or may not be a BIOS device. All handles associated with
  213.  * the device are closed, and all directories invalidated. This routine
  214.  * does all the dirty work, and is called automatically when
  215.  * disk_changed detects a media change.
  216.  */
  217.  
  218. void ARGS_ON_STACK 
  219. changedrv(d)
  220.     unsigned d;
  221. {
  222.     PROC *p;
  223.     int i;
  224.     FILEPTR *f;
  225.     FILESYS *fs;
  226.     DIR *dirh;
  227.     fcookie dir;
  228.     int warned = (d & 0xf000) == PROC_BASE_DEV;
  229.     long r;
  230.  
  231. /* if an aliased drive, change the *real* device */
  232.     if (d < NUM_DRIVES && aliasdrv[d]) {
  233.         d = aliasdrv[d] - 1;    /* see NOTE above */
  234.     }
  235.  
  236. /* re-initialize the device, if it was a BIOS device */
  237.     if (d < NUM_DRIVES) {
  238.         fs = drives[d];
  239.         if (fs) {
  240.             (void)(*fs->dskchng)(d);
  241.         }
  242.         init_drive(d);
  243.     }
  244.  
  245.     for (p = proclist; p; p = p->gl_next) {
  246.     /* invalidate all open files on this device */
  247.         for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  248.             if (((f = p->handle[i]) != 0) && (f->fc.dev == d)) {
  249.                 if (!warned) {
  250.                 ALERT(
  251. "Files were open on a changed drive (0x%x)!", d);
  252.                 warned++;
  253.                 }
  254.  
  255. /* we set f->dev to NULL to indicate to do_pclose that this is an
  256.  * emergency close, and that it shouldn't try to make any
  257.  * calls to the device driver since the file has gone away
  258.  */
  259.                 f->dev = NULL;
  260.                 (void)do_pclose(p, f);
  261. /* we could just zero the handle, but this could lead to confusion if
  262.  * a process doesn't realize that there's been a media change, Fopens
  263.  * a new file, and gets the same handle back. So, we force the
  264.  * handle to point to /dev/null.
  265.  */
  266.                 p->handle[i] =
  267.                 do_open("U:\\DEV\\NULL", O_RDWR, 0, (XATTR *)0);
  268.             }
  269.         }
  270.  
  271.     /* terminate any active directory searches on the drive */
  272.     /* BUG: This handles only Fsfirst/Fsnext searches! */
  273.         for (i = 0; i < NUM_SEARCH; i++) {
  274.             dirh = &p->srchdir[i];
  275.             if (dirh->fc.fs && dirh->fc.dev == d) {
  276.                 TRACE(("closing search for process %d", p->pid));
  277.                 dirh->fc.fs = 0;
  278.                 p->srchdta[i] = 0;
  279.             }
  280.         }
  281.  
  282.         if (d >= NUM_DRIVES) continue;
  283.  
  284.     /* change any active directories on the device to the (new) root */
  285.         fs = drives[d];
  286.         if (fs) {
  287.             r = (*fs->root)(d, &dir);
  288.             if (r != E_OK) dir.fs = 0;
  289.         } else {
  290.             dir.fs = 0; dir.dev = d;
  291.         }
  292.  
  293.         for (i = 0; i < NUM_DRIVES; i++) {
  294.             if (p->root[i].dev == d)
  295.                 p->root[i] = dir;
  296.             if (p->curdir[i].dev == d)
  297.                 p->curdir[i] = dir;
  298.         }
  299.     }
  300. }
  301.  
  302. /*
  303.  * check for media change: if the drive has changed, call changedrv to
  304.  * invalidate any open files and file handles associated with it, and
  305.  * call the file system's media change routine.
  306.  * returns: 0 if no change, 1 if change
  307.  */
  308.  
  309. int
  310. disk_changed(d)
  311.     int d;
  312. {
  313.     short r;
  314.     FILESYS *fs;
  315.     static char tmpbuf[8192];
  316.  
  317. /* for now, only check BIOS devices */
  318.     if (d < 0 || d >= NUM_DRIVES)
  319.         return 0;
  320. /* watch out for aliased drives */
  321.     if (aliasdrv[d]) {
  322.         d = aliasdrv[d] - 1;
  323.         if (d < 0 || d >= NUM_DRIVES)
  324.             return 0;
  325.     }
  326.  
  327. /* has the drive been initialized yet? If not, then initialize it and return
  328.  * "no change"
  329.  */
  330.     fs = drives[d];
  331.     if (!fs) {
  332.         TRACE(("drive %c not yet initialized", d+'A'));
  333.         changedrv(d);
  334.         return 0;
  335.     }
  336.  
  337. /* We have to do this stuff no matter what, because someone may have installed
  338.  * vectors to force a media change...
  339.  * PROBLEM: AHDI may get upset if the drive isn't valid.
  340.  * SOLUTION: don't change the default PSEUDODRIVES setting!
  341.  */
  342.     r = mediach(d);
  343.     if (r == 1) {        /* drive _may_ have changed */
  344.         r = rwabs(0, tmpbuf, 1, 0, d, 0L);    /* check the BIOS */
  345.         if (r != E_CHNG) {            /* nope, no change */
  346.             return 0;
  347.         }
  348.         r = 2;            /* drive was definitely changed */
  349.     }
  350.     if (r == 2) {
  351.         fs = drives[d];        /* get filesystem associated with drive */
  352.         if ((*fs->dskchng)(d)) { /* does the fs agree that it changed? */
  353.             drives[d] = 0;
  354.             changedrv(d);    /* yes -- do the change */
  355.             return 1;
  356.         }
  357.     }
  358.     return 0;
  359. }
  360.  
  361. /*
  362.  * routines for parsing path names
  363.  */
  364.  
  365. char temp1[PATH_MAX];    /* temporary storage for file names */
  366.  
  367. #define DIRSEP(p) ((p) == '\\')
  368.  
  369. /*
  370.  * relpath2cookie converts a TOS file name into a file cookie representing
  371.  * the directory the file resides in, and a character string representing
  372.  * the name of the file in that directory. The character string is
  373.  * copied into the "lastname" array. If lastname is NULL, then the cookie
  374.  * returned actually represents the file, instead of just the directory
  375.  * the file is in.
  376.  *
  377.  * note that lastname, if non-null, should be big enough to contain all the
  378.  * characters in "path", since if the file system doesn't want the kernel
  379.  * to do path name parsing we may end up just copying path to lastname
  380.  * and returning the current or root directory, as appropriate
  381.  *
  382.  * "relto" is the directory relative to which the search should start.
  383.  * if you just want the current directory, use path2cookie instead.
  384.  *
  385.  * "depth" is used to control recursion in symbolic links; if it exceeds
  386.  * MAX_LINKS, we return ELOOP.
  387.  *
  388.  * N.B.: "depth" is also overloaded to control whether drive letter
  389.  * interpretation is performed; if drive == 0, it is assumed that
  390.  * drive letters should _not_ be interpreted; if drive > 0, it
  391.  * is assumed that they should be, since we are in this case following
  392.  * a symbolic link.
  393.  */
  394.  
  395. #define MAX_LINKS 4
  396.  
  397. long
  398. relpath2cookie(relto, path, lastname, res, depth)
  399.     fcookie *relto;
  400.     const char *path;
  401.     char *lastname;
  402.     fcookie *res;
  403.     int depth;
  404. {
  405.     static fcookie dir;
  406.     int drv;
  407.     int len;
  408.     char c, *s;
  409.     XATTR xattr;
  410.     static char newpath[16] = "U:\\DEV\\";
  411.     char temp2[PATH_MAX];
  412.     char linkstuff[PATH_MAX];
  413.     long r = 0;
  414.  
  415. /* dolast: 0 == return a cookie for the directory the file is in
  416.  *         1 == return a cookie for the file itself, don't follow links
  417.  *       2 == return a cookie for whatever the file points at
  418.  */
  419.     int dolast = 0;
  420.     int i = 0;
  421.  
  422. TRACE(("relpath2cookie(%s)", path));
  423.  
  424.     if (depth > MAX_LINKS) return ELOOP;
  425.  
  426.     if (!lastname) {
  427.         dolast = 1;
  428.         lastname = temp2;
  429.     } else if (lastname == follow_links) {
  430.         dolast = 2;
  431.         lastname = temp2;
  432.     }
  433.  
  434.     *lastname = 0;
  435.  
  436. /* special cases: CON:, AUX:, etc. should be converted to U:\DEV\CON,
  437.  * U:\DEV\AUX, etc.
  438.  */
  439.     if (strlen(path) == 4 && path[3] == ':') {
  440.         strncpy(newpath+7, path, 3);
  441.         path = newpath;
  442.     }
  443.  
  444. /* first, check for a drive letter */
  445. /* BUG: a '\' at the start of a symbolic link is relative to the current
  446.  * drive of the process, not the drive the link is located on
  447.  */
  448.     if (path[1] == ':' && depth > 0) {
  449.         c = path[0];
  450.         if (c >= 'a' && c <= 'z')
  451.             drv = c - 'a';
  452.         else if (c >= 'A' && c <= 'Z')
  453.             drv = c - 'A';
  454.         else
  455.             goto nodrive;
  456.         path += 2;
  457.         i = 1;        /* remember that we saw a drive letter */
  458.     } else {
  459. nodrive:
  460.         drv = curproc->curdrv;
  461.     }
  462.  
  463. /* see if the path is rooted from '\\' */
  464.     if (DIRSEP(*path)) {
  465.         while(DIRSEP(*path))path++;
  466.         dir = curproc->root[drv];
  467.     } else {
  468.         if (i)    {    /* an explicit drive letter was given */
  469.             dir = curproc->curdir[drv];
  470.         }
  471.         else
  472.             dir = *relto;
  473.     }
  474.  
  475.     if (!dir.fs) {
  476.         changedrv(dir.dev);
  477.         dir = curproc->root[drv];
  478.     }
  479.  
  480.     if (!dir.fs) {
  481.         DEBUG(("path2cookie: no file system"));
  482.         return EDRIVE;
  483.     }
  484.  
  485.     *res = dir;
  486.     if (!*path) {        /* nothing more to do */
  487.         return 0;
  488.     }
  489.  
  490.     /* here's where we come when we've gone across a mount point */
  491.     
  492. restart_mount:
  493.  
  494. /* see if there has been a disk change; if so, return E_CHNG.
  495.  * path2cookie will restart the search automatically; other functions
  496.  * that call relpath2cookie directly will have to fail gracefully
  497.  */
  498.     if (disk_changed(dir.dev)) {
  499.         return E_CHNG;
  500.     }
  501.  
  502.     if (dir.fs->fsflags & FS_KNOPARSE) {
  503.         if (!dolast) {
  504.             strncpy(lastname, path, PATH_MAX-1);
  505.             lastname[PATH_MAX - 1] = 0;
  506.             r = 0;
  507.         } else {
  508.             r = (*dir.fs->lookup)(&dir, path, res);
  509.         }
  510.         goto check_for_mount;
  511.     }
  512.  
  513. /* parse all but (possibly) the last component of the path name */
  514.  
  515.     for(;;) {
  516.     /* if nothing left in path, and we don't care about links,
  517.      * then we're finished
  518.      */
  519.         if (dolast < 2 && !*path) {
  520.             dir = *res;
  521.             break;
  522.         }
  523.     /* first, check to see if we're allowed to read this link/directory
  524.      * NOTE: at this point, "res" contains the new 'directory', and
  525.      * "dir" contains the old directory we were in (in case we need
  526.      * to call relpath2cookie on a link)
  527.      */
  528.         r = (res->fs->getxattr)(res, &xattr);
  529.         if (r != 0) {
  530.             DEBUG(("path2cookie: couldn't get file attributes"));
  531.             break;
  532.         }
  533.     /* if the "directory" is a link, follow it */
  534.         i = depth;
  535.         while ( (xattr.mode & S_IFMT) == S_IFLNK ) {
  536.             if (i++ > MAX_LINKS)
  537.                 return ELOOP;
  538.             r = (res->fs->readlink)(res, linkstuff, PATH_MAX);
  539.             if (r) {
  540.                 DEBUG(("error reading symbolic link"));
  541.                 break;
  542.             }
  543.             r = relpath2cookie(&dir, linkstuff, follow_links, res,
  544.                         depth+1);
  545.             if (r) {
  546.                 DEBUG(("error following symbolic link"));
  547.                 break;
  548.             }
  549.             (void)(res->fs->getxattr)(res, &xattr);
  550.         }
  551.  
  552.     /* if there's nothing left in the path, we can break here */
  553.         if (!*path) {
  554.             dir = *res;
  555.             break;
  556.         }
  557.  
  558.     /* the "directory" had better, in fact, be a directory */
  559.         if ( (xattr.mode & S_IFMT) != S_IFDIR ) {
  560.             return EPTHNF;
  561.          }
  562.     /* and we had better have search permission to it */
  563.         if (denyaccess(&xattr, S_IXOTH)) {
  564.             DEBUG(("search permission in directory denied"));
  565.             return EPTHNF;
  566.         }
  567.  
  568.         dir = *res;
  569.  
  570.     /* next, peel off the next name in the path */
  571.         len = 0;
  572.         s = lastname;
  573.         c = *path;
  574.         while (c && !DIRSEP(c)) {
  575.             if (len++ < PATH_MAX)
  576.                 *s++ = c;
  577.             c = *++path;
  578.         }
  579.         *s = 0;
  580.         while(DIRSEP(*path))path++;
  581.  
  582.     /* if there are no more names in the path, then we may be done */
  583.         if (dolast == 0 && !*path)
  584.             break;
  585.  
  586.         r = (*dir.fs->lookup)(&dir, lastname, res);
  587.         if (r) {        /* error? */
  588.             DEBUG(("path2cookie: lookup returned %ld", r));
  589.             dir = *res;
  590.             break;
  591.         }
  592.     }
  593.  
  594. check_for_mount:
  595.  
  596.     if (r == EMOUNT) {    /* hmmm... a ".." at a mount point, maybe */
  597.         fcookie mounteddir;
  598.         r = (*dir.fs->root)(dir.dev, &mounteddir);
  599.         if (r == 0 && drv == UNIDRV) {
  600.             if (dir.fs == mounteddir.fs &&
  601.                 dir.index == mounteddir.index &&
  602.                 dir.dev == mounteddir.dev) {
  603.                 *res = dir = curproc->root[UNIDRV];
  604.             TRACE(("path2cookie: restarting from mount point"));
  605.                 goto restart_mount;
  606.             }
  607.         }
  608.         else r = 0;
  609.     }
  610.  
  611.     return r;
  612. }
  613.  
  614. #define MAX_TRYS 8
  615.  
  616. long
  617. path2cookie(path, lastname, res)
  618.     const char *path;
  619.     char *lastname;
  620.     fcookie *res;
  621. {
  622.     fcookie *dir;
  623.     long r;
  624. /* AHDI sometimes will keep insisting that a media change occured;
  625.  * we limit the number or retrys to avoid hanging the system
  626.  */
  627.     int trycnt = 0;
  628.  
  629.     dir = &curproc->curdir[curproc->curdrv];
  630.  
  631.     do {
  632.     /* NOTE: depth == 1 is necessary; see the comments before relpath2cookie */
  633.         r = relpath2cookie(dir, path, lastname, res, 1);
  634.         if (r == E_CHNG)
  635.             DEBUG(("path2cookie: restarting due to media change"));
  636.     } while (r == E_CHNG && trycnt++ < MAX_TRYS);
  637.  
  638.     return r;
  639. }
  640.  
  641. /*
  642.  * new_fileptr, dispose_fileptr: allocate (deallocate) a file pointer
  643.  */
  644.  
  645. FILEPTR *
  646. new_fileptr()
  647. {
  648.     FILEPTR *f;
  649.  
  650.     if ((f = flist) != 0) {
  651.         flist = f->next;
  652.         f->next = 0;
  653.         return f;
  654.     }
  655.     f = kmalloc(SIZEOF(FILEPTR));
  656.     if (!f) {
  657.         FATAL("new_fileptr: out of memory");
  658.     }
  659.     else {
  660.         f->next = 0;
  661.     }
  662.     return f;
  663. }
  664.  
  665. void
  666. dispose_fileptr(f)
  667.     FILEPTR *f;
  668. {
  669.     if (f->links != 0) {
  670.         FATAL("dispose_fileptr: f->links == %d", f->links);
  671.     }
  672.     f->next = flist;
  673.     flist = f;
  674. }
  675.  
  676. /*
  677.  * denyshare(list, f): "list" points at the first FILEPTR in a
  678.  * chained list of open FILEPTRS referring to the same file;
  679.  * f is a newly opened FILEPTR. Every FILEPTR in the given list is
  680.  * checked to see if its "open" mode (in list->flags) is compatible with
  681.  * the open mode in f->flags. If not (for example, if f was opened with
  682.  * a "read" mode and some other file has the O_DENYREAD share mode),
  683.  * then 1 is returned. If all the open FILEPTRs in the list are
  684.  * compatible with f, then 0 is returned.
  685.  * This is not as complicated as it sounds. In practice, just keep a
  686.  * list of open FILEPTRs attached to each file, and put something like
  687.  *     if (denyshare(thisfile->openfileptrlist, newfileptr))
  688.  *        return EACCDN;
  689.  * in the device open routine.
  690.  */
  691.  
  692. int ARGS_ON_STACK 
  693. denyshare(list, f)
  694.     FILEPTR *list, *f;
  695. {
  696.     int newrm, newsm;
  697.     int oldrm, oldsm;
  698.     int i;
  699.  
  700.     newrm = f->flags & O_RWMODE;
  701.     newsm = f->flags & O_SHMODE;
  702.  
  703.     for ( ; list; list = list->next) {
  704.         oldrm = list->flags & O_RWMODE;
  705.         oldsm = list->flags & O_SHMODE;
  706.         if (oldsm == O_DENYW || oldsm == O_DENYRW) {
  707.              if (newrm != O_RDONLY && newrm != O_EXEC) {
  708.                 DEBUG(("write access denied"));
  709.                 return 1;
  710.             }
  711.         }
  712.         if (oldsm == O_DENYR || oldsm == O_DENYRW) {
  713.             if (newrm != O_WRONLY) {
  714.                 DEBUG(("read access denied"));
  715.                 return 1;
  716.             }
  717.         }
  718.         if (newsm == O_DENYW || newsm == O_DENYRW) {
  719.             if (oldrm != O_RDONLY && oldrm != O_EXEC) {
  720.                 DEBUG(("couldn't deny writes"));
  721.                 return 1;
  722.             }
  723.         }
  724.         if (newsm == O_DENYR || newsm == O_DENYRW) {
  725.             if (oldrm != O_WRONLY) {
  726.                 DEBUG(("couldn't deny reads"));
  727.                 return 1;
  728.             }
  729.         }
  730. /* If either sm == O_COMPAT, then we check to make sure
  731.    that the file pointers are owned by the same process (O_COMPAT means
  732.    "deny access to any other processes"). Also, once a file is opened
  733.    in compatibility mode, it can't be opened in any other mode.
  734.  */
  735.         if (newsm == O_COMPAT || oldsm == O_COMPAT) {
  736.             if (newsm != O_COMPAT || oldsm != O_COMPAT) {
  737.                 DEBUG(("O_COMPAT mode conflict"));
  738.                 return 1;
  739.             }
  740.             for (i = MIN_HANDLE; i < MAX_OPEN; i++) {
  741.                 if (curproc->handle[i] == list)
  742.                     goto found;
  743.             }
  744.         /* old file pointer is not open by this process */
  745.             DEBUG(("O_COMPAT file was opened by another process"));
  746.             return 1;
  747.         found:
  748.             ;    /* everything is OK */
  749.         }
  750.     }
  751.     return 0;
  752. }
  753.  
  754. /*
  755.  * denyaccess(XATTR *xattr, unsigned perm): checks to see if the access
  756.  * specified by perm (which must be some combination of S_IROTH, S_IWOTH,
  757.  * and S_IXOTH) should be granted to the current process
  758.  * on a file with the given extended attributes. Returns 0 if access
  759.  * by the current process is OK, 1 if not.
  760.  */
  761.  
  762. int
  763. denyaccess(xattr, perm)
  764.     XATTR *xattr;
  765.     unsigned perm;
  766. {
  767.     unsigned mode;
  768.  
  769. /* the super-user can do anything! */
  770.     if (curproc->euid == 0)
  771.         return 0;
  772.  
  773.     mode = xattr->mode;
  774.     if (curproc->euid == xattr->uid)
  775.         perm = perm << 6;
  776.     else if (curproc->egid == xattr->gid)
  777.         perm = perm << 3;
  778.     if ((mode & perm) != perm) return 1;    /* access denied */
  779.     return 0;
  780. }
  781.  
  782. /*
  783.  * Checks a lock against a list of locks to see if there is a conflict.
  784.  * This is a utility to be used by file systems, somewhat like denyshare
  785.  * above. Returns 0 if there is no conflict, or a pointer to the
  786.  * conflicting LOCK structure if there is.
  787.  *
  788.  * Conflicts occur for overlapping locks if the process id's are
  789.  * different and if at least one of the locks is a write lock.
  790.  *
  791.  * NOTE: we assume before being called that the locks have been converted
  792.  * so that l_start is absolute. not relative to the current position or
  793.  * end of file.
  794.  */
  795.  
  796. LOCK * ARGS_ON_STACK 
  797. denylock(list, lck)
  798.     LOCK *list, *lck;
  799. {
  800.     LOCK *t;
  801.     unsigned long tstart, tend;
  802.     unsigned long lstart, lend;
  803.     int pid = curproc->pid;
  804.     int ltype;
  805.  
  806.     ltype = lck->l.l_type;
  807.     lstart = lck->l.l_start;
  808.  
  809.     if (lck->l.l_len == 0)
  810.         lend = 0xffffffffL;
  811.     else
  812.         lend = lstart + lck->l.l_len;
  813.  
  814.     for (t = list; t; t = t->next) {
  815.         tstart = t->l.l_start;
  816.         if (t->l.l_len == 0)
  817.             tend = 0xffffffffL;
  818.         else
  819.             tend = tstart + t->l.l_len;
  820.  
  821.     /* look for overlapping locks */
  822.         if (tstart <= lstart && tend >= lstart && t->l.l_pid != pid &&
  823.             (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
  824.             break;
  825.         if (lstart <= tstart && lend >= tstart && t->l.l_pid != pid &&
  826.             (ltype == F_WRLCK || t->l.l_type == F_WRLCK))
  827.             break;
  828.     }
  829.     return t;
  830. }
  831.  
  832. /*
  833.  * check to see that a file is a directory, and that write permission
  834.  * is granted; return an error code, or 0 if everything is ok.
  835.  */
  836. long
  837. dir_access(dir, perm)
  838.     fcookie *dir;
  839.     unsigned perm;
  840. {
  841.     XATTR xattr;
  842.     long r;
  843.  
  844.     r = (*dir->fs->getxattr)(dir, &xattr);
  845.     if (r) return r;
  846.     if ( (xattr.mode & S_IFMT) != S_IFDIR ) {
  847.         DEBUG(("file is not a directory"));
  848.         return EPTHNF;
  849.     }
  850.     if (denyaccess(&xattr, perm)) {
  851.         DEBUG(("no permission for directory"));
  852.         return EACCDN;
  853.     }
  854.     return 0;
  855. }
  856.  
  857. /*
  858.  * returns 1 if the given name contains a wildcard character 
  859.  */
  860.  
  861. int
  862. has_wild(name)
  863.     const char *name;
  864. {
  865.     char c;
  866.  
  867.     while ((c = *name++) != 0) {
  868.         if (c == '*' || c == '?') return 1;
  869.     }
  870.     return 0;
  871. }
  872.  
  873. /*
  874.  * void copy8_3(dest, src): convert a file name (src) into DOS 8.3 format
  875.  * (in dest). Note the following things:
  876.  * if a field has less than the required number of characters, it is
  877.  * padded with blanks
  878.  * a '*' means to pad the rest of the field with '?' characters
  879.  * special things to watch for:
  880.  *    "." and ".." are more or less left alone
  881.  *    "*.*" is recognized as a special pattern, for which dest is set
  882.  *    to just "*"
  883.  * Long names are truncated. Any extensions after the first one are
  884.  * ignored, i.e. foo.bar.c -> foo.bar, foo.c.bar->foo.c.
  885.  */
  886.  
  887. void
  888. copy8_3(dest, src)
  889.     char *dest;
  890.     const char *src;
  891. {
  892.     char fill = ' ', c;
  893.     int i;
  894.  
  895.     if (src[0] == '.') {
  896.         if (src[1] == 0) {
  897.             strcpy(dest, ".       .   ");
  898.             return;
  899.         }
  900.         if (src[1] == '.' && src[2] == 0) {
  901.             strcpy(dest, "..      .   ");
  902.             return;
  903.         }
  904.     }
  905.     if (src[0] == '*' && src[1] == '.' && src[2] == '*' && src[3] == 0) {
  906.         dest[0] = '*';
  907.         dest[1] = 0;
  908.         return;
  909.     }
  910.  
  911.     for (i = 0; i < 8; i++) {
  912.         c = *src++;
  913.         if (!c || c == '.') break;
  914.         if (c == '*') {
  915.             fill = c = '?';
  916.         }
  917.         *dest++ = toupper(c);
  918.     }
  919.     while (i++ < 8) {
  920.         *dest++ = fill;
  921.     }
  922.     *dest++ = '.';
  923.     i = 0;
  924.     fill = ' ';
  925.     while (c && c != '.')
  926.         c = *src++;
  927.  
  928.     if (c) {
  929.         for( ;i < 3; i++) {
  930.             c = *src++;
  931.             if (!c || c == '.') break;
  932.             if (c == '*')
  933.                 c = fill = '?';
  934.             *dest++ = toupper(c);
  935.         }
  936.     }
  937.     while (i++ < 3)
  938.         *dest++ = fill;
  939.     *dest = 0;
  940. }
  941.  
  942. /*
  943.  * int pat_match(name, patrn): returns 1 if "name" matches the template in
  944.  * "patrn", 0 if not. "patrn" is assumed to have been expanded in 8.3
  945.  * format by copy8_3; "name" need not be. Any '?' characters in patrn
  946.  * will match any character in name. Note that if "patrn" has a '*' as
  947.  * the first character, it will always match; this will happen only if
  948.  * the original pattern (before copy8_3 was applied) was "*.*".
  949.  *
  950.  * BUGS: acts a lot like the silly TOS pattern matcher.
  951.  */
  952.  
  953. int
  954. pat_match(name, template)
  955.     const char *name, *template;
  956. {
  957.     register char *s, c;
  958.     char expname[TOS_NAMELEN+1];
  959.  
  960.     if (*template == '*') return 1;
  961.     copy8_3(expname, name);
  962.  
  963.     s = expname;
  964.     while ((c = *template++) != 0) {
  965.         if (c != *s && c != '?')
  966.             return 0;
  967.         s++;
  968.     }
  969.     return 1;
  970. }
  971.  
  972. /*
  973.  * int samefile(fcookie *a, fcookie *b): returns 1 if the two cookies
  974.  * refer to the same file or directory, 0 otherwise
  975.  */
  976.  
  977. int
  978. samefile(a, b)
  979.     fcookie *a, *b;
  980. {
  981.     if (a->fs == b->fs && a->dev == b->dev && a->index == b->index)
  982.         return 1;
  983.     return 0;
  984. }
  985.